package cs342.project1.mathNotebook.gui;

import cs342.project1.mathNotebook.data.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.security.*;
import java.sql.*;

import java.awt.RenderingHints.Key;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.DecimalFormat;
import java.util.ArrayList;


public class CreateScreen extends JFrame {

    private final int width = 400, height = 150;
    private JLabel usernameLabel, passwordLabel, passwordConfirmLabel;
    private JTextField usernameField;
    private JPasswordField passwordField, passwordFieldConfirm;
    private JButton createButton, cancelButton;
    private PublicKey publicKey;
    private PrivateKey privateKey;
    
    public CreateScreen() {
        
        this.setSize(width, height);
	this.setTitle("Create New Account");
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
	this.setLayout(new GridLayout(4,2));

	usernameLabel = new JLabel("User Name:");
	this.add(usernameLabel);
	
	usernameField = new JTextField();
	this.add(usernameField);

	passwordLabel = new JLabel("Password:");
	this.add(passwordLabel);
	
	passwordField = new JPasswordField();
	this.add(passwordField);
	
	passwordConfirmLabel = new JLabel("Confirm Password:");
	this.add(passwordConfirmLabel);
	
	passwordFieldConfirm = new JPasswordField();
	this.add(passwordFieldConfirm);

	createButton = new JButton("Create Account");
	createButton.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent ae) {
		try{
			hitCreate();
		}catch(Exception ex){
			ex.printStackTrace();
		}
	}});
	this.add(createButton);

	cancelButton = new JButton("Cancel");
	cancelButton.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {hitCancel();}});
	this.add(cancelButton);
    }

    private void hitCreate() throws SQLException{
        
        String password1 = new String(passwordField.getPassword());
        String password2 = new String(passwordFieldConfirm.getPassword());
        
        // Check to see if passwords match.
        if (password1.equals(password2)) {
            
            // Input information into database.
            MathDatabase mdb = new MathDatabase();
            mdb.open();
            mdb.getStatement().executeQuery("SELECT * FROM Users WHERE username = "+'"' + usernameField.getText() + '"');
            ResultSet rs = mdb.getStatement().getResultSet();
            if (rs.next()){
                usernameField.setText("Name already in use!");
            } else{
                
                // Create Users public and private keys
                try {
                    KeyPairGenerator kg = KeyPairGenerator.getInstance("rsa");
                    SecureRandom secureSeed = SecureRandom.getInstance("SHA1PRNG");
                    
                    String seedForKey = password1;
                    int keySize = 512;
                    
                    byte [] keyData = seedForKey.getBytes();
                    secureSeed.setSeed(keyData);
                    kg.initialize(keySize , secureSeed);
                    KeyPair pair = kg.generateKeyPair();
                    PrivateKey priKey = pair.getPrivate();
                    PublicKey pubKey = pair.getPublic();
                    String fl = "private.key";
                    FileOutputStream out = new FileOutputStream(fl);
                    byte [] ky = priKey.getEncoded();
                    out.write(ky);
                    out.close();
                    fl = "public.key";
                    out = new FileOutputStream(fl);
                    ky = pubKey.getEncoded();
                    out.write(ky);
                    out.close();
                    
                    /*
                    keyGen.initialize(1024);
                    KeyPair keypair = keyGen.genKeyPair();
                    KeyFactory fact = KeyFactory.getInstance("rsa");
                    RSAPublicKeySpec pub = fact.getKeySpec(keypair.getPublic(),
                        RSAPublicKeySpec.class);
                    RSAPrivateKeySpec priv = fact.getKeySpec(keypair.getPrivate(),
                        RSAPrivateKeySpec.class);

                    saveToFile("public.key", pub.getModulus(),
                        pub.getPublicExponent());
                    saveToFile("private.key", priv.getModulus(),
                        priv.getPrivateExponent());
                    */
                }
                catch (java.security.NoSuchAlgorithmException e) {
                    JOptionPane.showMessageDialog(this, "Unable to create public and private key pair.");
                }
                catch (IOException e) {
                    JOptionPane.showMessageDialog(this, "File IO exception has been thrown.");
                }
                
                try {
                    String passwordString = new String(passwordField.getPassword());
                    PreparedStatement ps = mdb.createPreparedStatement("INSERT INTO Users(username, password, pubKey, priKey) VALUES(?,?,?,?)");
                    ps.setString(1,usernameField.getText());
                    ps.setString(2,passwordString);
                    ps.setBinaryStream(3,new FileInputStream("public.key"),(int) new File("public.key").length());
                    ps.setBinaryStream(4,new FileInputStream("private.key"),(int) new File("private.key").length());
                    
                    ps.executeUpdate();
                    mdb.commit();
                    
                    this.dispose();
                    new LoginScreen().setVisible(true);
                }
                catch (IOException e) {
                    JOptionPane.showMessageDialog(this, "File IO exception has been thrown.");
                }
            }
            mdb.close();
        }
        
        // delete files
        else {
            JOptionPane.showMessageDialog(this, "Passwords do not match!");
        }
    }

    public void saveToFile(String fileName,
            BigInteger mod, BigInteger exp) throws IOException {
            ObjectOutputStream oout = new ObjectOutputStream(
                new BufferedOutputStream(new FileOutputStream(fileName)));
            try {
                oout.writeObject(mod);
                oout.writeObject(exp);
            } catch (Exception e) {
                throw new IOException("Unexpected error", e);
            } finally {
                oout.close();
            }
        }
    
    private void hitCancel(){
	this.dispose();
	new StartScreen().setVisible(true);
    }
}